
package com.xifan.myaccount.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;

import com.xifan.myaccount.entity.Account;
import com.xifan.myaccount.entity.RecordDetail;
import com.xifan.myaccount.entity.RecordType;
import com.xifan.myaccount.util.Util;

import java.util.ArrayList;
import java.util.List;

public class DatabaseImpl extends SqlHelper {

    private boolean mPersistDB;

    /**
     * Set DB persists on every operation.
     */
    public void setPersistDB(boolean mPersistDB) {
        this.mPersistDB = mPersistDB;
    }

    /**
     * Open database,if persists is true, DB will not be closed after opertions
     * till call close manually or GC. Don't forget close db after all opertion
     * done.
     * 
     * @param persists whether the DB is persist on every operation.
     */
    public DatabaseImpl(Context context, boolean persists) {
        super(context, SqlHelper.DB_NAME_ACCOUNT, null, SqlHelper.DB_VERSION);
        setPersistDB(persists);
    }

    /**
     * Open database with one-shot,DB will be closed after every operation.
     */
    public DatabaseImpl(Context context) {
        this(context, false);
    }

    /**
     * @param key the key you want to get
     * @param table The table name you want to query
     * @param whereClause clauses with "where"
     * @param isDesc return list order by desc or not
     * @return the list of key result
     */
    public List doQuery(String key, String table, String whereClause, boolean isDesc) {
        Cursor c = doQuery("select " + key + " from " + table + " " + whereClause, null);
        List list = new ArrayList();
        if (c != null && c.getCount() > 0) {
            boolean canLoop;
            if (isDesc) {
                c.moveToLast();
                canLoop = !c.isBeforeFirst();
            } else {
                c.moveToFirst();
                canLoop = !c.isAfterLast();
            }
            while (canLoop) {
                if (table.equals(DB_TABLE_DETAIL)) {
                    RecordDetail detail = new RecordDetail();
                    detail.setId(c.getInt(c.getColumnIndex("id")));
                    detail.setAccountId(c.getInt(c.getColumnIndex("accountId")));
                    detail.setDate(c.getString(c.getColumnIndex("recordDate")));
                    detail.setLocation(c.getString(c.getColumnIndex("location")));
                    detail.setMoney(c.getFloat(c.getColumnIndex("moneyAmount")));
                    detail.setNote(c.getString(c.getColumnIndex("note")));
                    detail.setPicUri(c.getString(c.getColumnIndex("picUri")));
                    detail.setRecordType(c.getInt(c.getColumnIndex("recordType")));
                    detail.setOperateType(c.getInt(c.getColumnIndex("recordOp")));
                    detail.setReimbursabled(c.getInt(c.getColumnIndex("isReimbursabled")));
                    detail.setState(0);
                    list.add(detail);
                } else if (table.equals(DB_TABLE_ACCOUNT)) {
                    Account account = new Account();
                    account.setAccountName(c.getString(c.getColumnIndex("accountName")));
                    account.setAccountType(c.getInt(c.getColumnIndex("accountType")));
                    account.setTotal(c.getFloat(c.getColumnIndex("total")));
                    account.setExpend(c.getFloat(c.getColumnIndex("expend")));
                    account.setRevenue(c.getFloat(c.getColumnIndex("revenue")));
                    account.setId(c.getInt(c.getColumnIndex("id")));
                    list.add(account);
                } else if (table.equals(DB_TABLE_TYPE)) {
                    RecordType type = new RecordType();
                    type.typeId = c.getInt(c.getColumnIndex("id"));
                    type.typeName = c.getString(c.getColumnIndex("type_name"));
                    type.typePinyin = c.getString(c.getColumnIndex("type_pinyin"));
                    type.lastDate = c.getString(c.getColumnIndex("last_date"));
                    type.frequency = c.getInt(c.getColumnIndex("freq"));
                    type.stamp = c.getString(c.getColumnIndex("event_stamp"));
                    type.opType = c.getInt(c.getColumnIndex("operate_type"));
                    list.add(type);
                } else if (table.equals(DB_TABLE_ACCOUNT_TYPE)) {
                    list.add(c.getString(c.getColumnIndex("typename")));
                }
                if (isDesc) {
                    c.moveToPrevious();
                    canLoop = !c.isBeforeFirst();
                } else {
                    c.moveToNext();
                    canLoop = !c.isAfterLast();
                }
            }
        }
        if (!mPersistDB)
            close();
        c.close(); // close cursor anyway.
        return list;
    }

    /**
     * @param table The table name you want to query
     * @param whereClause clauses with "where"
     * @param isDesc return list order by desc or not
     * @return the list of all result
     */
    public List doQuery(String table, String whereClause, boolean isDesc) {
        return doQuery("*", table, whereClause, isDesc);
    }

    public int doUpdate(String table, ContentValues values, String where, String[] args) {
        int code = super.doUpdate(table, values, where, args);
        if (!mPersistDB)
            close();
        return code;
    }

    public long doInsert(String table, ContentValues values) {
        long code = super.doInsert(table, values);
        if (!mPersistDB)
            close();
        return code;
    }

    public int doDelete(String table, String where, String[] args) {
        int code = super.doDelete(table, where, args);
        if (!mPersistDB)
            close();
        return code;
    }

    public void initDataBase() {
        super.initDataBase();
    }

    /**
     * The idea about add or delete while sync account, is simplely use reversed
     * number,and checked by reversed operator. like 1 means add expend item and
     * -1 means delete expend item.
     */
    public void syncAccount(float money, int typeId, int accountId, int operation) {
        Log.e("xifan", "Syncing account data");
        setPersistDB(true);

        List list = doQuery(DB_TABLE_ACCOUNT, "where id=" + accountId, false);
        Account account = (Account) list.get(0);

        ContentValues cv = new ContentValues();
        // Check if is operating deletion.
        final boolean isDel;
        if (isDel = operation < 0) {
            // swap operation
            operation = -operation == 2 ? 1 : 2;
        }

        if (operation == 1) {
            // 支出
            cv.put("expend", account.getExpend() + money);
            cv.put("total", account.getTotal() - money);
        } else if (operation == 2) {
            // 收入
            cv.put("revenue", account.getRevenue() + money);
            cv.put("total", account.getTotal() + money);
        }
        doUpdate("account", cv, "id=?", new String[] {
                String.valueOf(Account.DEFAULT_ACCOUNT_ID)
        });

        // Do not count type freqs if is operating delete.
        if (!isDel) {
            ContentValues typeValues = new ContentValues();
            typeValues.put("last_date", Util.getDatetime());

            list = doQuery(DB_TABLE_TYPE, "where operate_type=" + operation + " and id=" + typeId,
                    true);
            if (list.size() > 0) {
                typeValues.put("freq", ((RecordType) list.get(0)).frequency + 1);
            }
            doUpdate("record_type", typeValues, "id=?", new String[] {
                    String.valueOf(typeId)
            });
        }
    }

}
